#include <linux/kernel.h>
#include <linux/module.h>

#include <net/sock.h>
#include <net/netlink.h>

static struct sock *nl_sock;

DEFINE_MUTEX(nl_mutex);

static int recv_msg_cb(struct sk_buff *skb, struct nlmsghdr *nlh)
{
    int type;
    char *data;
    type = nlh->nlmsg_type;

    printk(KERN_ERR"%s MSG_TYPE: 0x%x \n", __func__, type);

    data = NLMSG_DATA(nlh);
    printk("%x %x %x %x\n", data[0], data[1], data[2], data[3]);

    return 0;
}

static void nl_recv_msg(struct sk_buff *skb)
{
    mutex_lock(&nl_mutex);
    netlink_rcv_skb(skb, &recv_msg_cb);
    mutex_unlock(&nl_mutex);
}

static int nl_init(void)
{
    struct netlink_kernel_cfg cfg = {
        .input  = nl_recv_msg,
        .groups = 1.
    };
    
    /*
     * Linux Kernel 3.7.10-1.1
     */
    nl_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
    if (!nl_sock) {
        printk(KERN_ERR"%s create netlink socket fail\n", __func__); 
        return -ENOMEM;
    }

    printk("%s insmod success\n", __func__);

    return 0;
}

static void nl_exit(void)
{
    if (nl_sock) {
        netlink_kernel_release(nl_sock);
    }

    printk("%s rmmod success\n", __func__);
}

module_init(nl_init);
module_exit(nl_exit);
MODULE_LICENSE("GPL");
